From 30ed8dac34a5a8e097484fa581afa9eb12b2429f Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 10 Feb 2006 00:16:53 +0100 Subject: [PATCH] Check the hypercall number in the privcmd hypercall ioctl. We check it is a member of a small set of permitted hypercalls. Fix libxenstat to not use multicalls (not permitted, and not need for efficiency in libxenstat). Based on an original patch by Chris Wright. Signed-off-by: Keir Fraser Signed-off-by: Chris Wright --- .../drivers/xen/privcmd/privcmd.c | 18 ++++++++ tools/xenstat/libxenstat/src/xen-interface.c | 43 +++++++++---------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index 7758ca5cd9..52364f9aeb 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -35,6 +35,9 @@ static struct proc_dir_entry *privcmd_intf; static struct proc_dir_entry *capabilities_intf; +#define NR_HYPERCALLS 32 +static DECLARE_BITMAP(hypercall_permission_map, NR_HYPERCALLS); + static int privcmd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) { @@ -48,6 +51,12 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, if (copy_from_user(&hypercall, udata, sizeof(hypercall))) return -EFAULT; + /* Check hypercall number for validity. */ + if (hypercall.op >= NR_HYPERCALLS) + return -EINVAL; + if (!test_bit(hypercall.op, hypercall_permission_map)) + return -EINVAL; + #if defined(__i386__) __asm__ __volatile__ ( "pushl %%ebx; pushl %%ecx; pushl %%edx; " @@ -260,6 +269,15 @@ static int capabilities_read(char *page, char **start, off_t off, static int __init privcmd_init(void) { + /* Set of hypercalls that privileged applications may execute. */ + set_bit(__HYPERVISOR_acm_op, hypercall_permission_map); + set_bit(__HYPERVISOR_dom0_op, hypercall_permission_map); + set_bit(__HYPERVISOR_event_channel_op, hypercall_permission_map); + set_bit(__HYPERVISOR_memory_op, hypercall_permission_map); + set_bit(__HYPERVISOR_mmu_update, hypercall_permission_map); + set_bit(__HYPERVISOR_mmuext_op, hypercall_permission_map); + set_bit(__HYPERVISOR_xen_version, hypercall_permission_map); + privcmd_intf = create_xen_proc_entry("privcmd", 0400); if (privcmd_intf != NULL) privcmd_intf->proc_fops = &privcmd_file_ops; diff --git a/tools/xenstat/libxenstat/src/xen-interface.c b/tools/xenstat/libxenstat/src/xen-interface.c index 8c06449db3..6b6fa6b9fb 100644 --- a/tools/xenstat/libxenstat/src/xen-interface.c +++ b/tools/xenstat/libxenstat/src/xen-interface.c @@ -61,43 +61,40 @@ static int xi_make_xen_version_hypercall(xi_handle *handle, long *vnum, xen_extraversion_t *ver) { privcmd_hypercall_t privcmd; - multicall_entry_t multicall[2]; int ret = 0; - /* set up for doing hypercall */ - privcmd.op = __HYPERVISOR_multicall; - privcmd.arg[0] = (unsigned long)multicall; - privcmd.arg[1] = 2; - - /* first one to get xen version number */ - multicall[0].op = __HYPERVISOR_xen_version; - multicall[0].args[0] = (unsigned long)XENVER_version; - - /* second to get xen version flag */ - multicall[1].op = __HYPERVISOR_xen_version; - multicall[1].args[0] = (unsigned long)XENVER_extraversion; - multicall[1].args[1] = (unsigned long)ver; - - if (mlock( &privcmd, sizeof(privcmd_hypercall_t)) < 0) { + if (mlock(&privcmd, sizeof(privcmd)) < 0) { perror("Failed to mlock privcmd structure"); return -1; } - if (mlock( multicall, sizeof(multicall_entry_t)) < 0) { - perror("Failed to mlock multicall_entry structure"); - munlock( &multicall, sizeof(multicall_entry_t)); + if (mlock(ver, sizeof(*ver)) < 0) { + perror("Failed to mlock extraversion structure"); + munlock(&privcmd, sizeof(privcmd)); return -1; } - if (ioctl( handle->fd, IOCTL_PRIVCMD_HYPERCALL, &privcmd) < 0) { + privcmd.op = __HYPERVISOR_xen_version; + privcmd.arg[0] = (unsigned long)XENVER_version; + privcmd.arg[1] = 0; + + *vnum = ioctl(handle->fd, IOCTL_PRIVCMD_HYPERCALL, &privcmd); + if (*vnum < 0) { perror("Hypercall failed"); ret = -1; } - *vnum = multicall[0].result; + privcmd.op = __HYPERVISOR_xen_version; + privcmd.arg[0] = (unsigned long)XENVER_extraversion; + privcmd.arg[1] = (unsigned long)ver; - munlock( &privcmd, sizeof(privcmd_hypercall_t)); - munlock( &multicall, sizeof(multicall_entry_t)); + if (ioctl(handle->fd, IOCTL_PRIVCMD_HYPERCALL, &privcmd) < 0) { + perror("Hypercall failed"); + ret = -1; + } + + munlock(&privcmd, sizeof(privcmd)); + munlock(ver, sizeof(*ver)); return ret; } -- 2.30.2